package com.imooc.bilibili.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.imooc.bilibili.dao.LoginInfoDao;
import com.imooc.bilibili.dao.RefreshTokenInfoDao;
import com.imooc.bilibili.dao.UserInfoDao;
import com.imooc.bilibili.entity.LoginInfo;
import com.imooc.bilibili.entity.RefreshTokenInfo;
import com.imooc.bilibili.entity.UserInfo;
import com.imooc.bilibili.entity.page.PageResult;
import com.imooc.bilibili.enums.DeleteStateEnums;
import com.imooc.bilibili.enums.EnableStateEnums;
import com.imooc.bilibili.enums.GenderEnums;
import com.imooc.bilibili.exception.ConditionException;
import com.imooc.bilibili.request.UserRequest;
import com.imooc.bilibili.service.UserAuthService;
import com.imooc.bilibili.service.UserService;
import com.imooc.bilibili.utils.JwtUtil;
import com.imooc.bilibili.utils.MD5Utils;
import com.imooc.bilibili.utils.RsaUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.sql.Timestamp;
import java.util.*;

@Service("userService")
public class UserServiceImpl implements UserService {

    @Autowired
    private UserInfoDao userInfoDao;

    @Autowired
    private LoginInfoDao loginInfoDao;

    @Autowired
    private UserAuthService userAuthService;

    @Autowired
    private RefreshTokenInfoDao refreshTokenInfoDao;

    @Override
    public void insertUserService(UserRequest req) {
        //获取注册用的手机号
        String loginPhone = req.getLoginPhone();
        if (StringUtils.isBlank(loginPhone)) {
            throw new ConditionException("手机号不能为空");
        }

        //根据手机号查询对应的登录信息
        LoginInfo dbLogin = this.queryUserByPhoneService(loginPhone);
        if (dbLogin != null) {
            throw new ConditionException("该手机号已经被注册");
        }

        //获取当前日期
        Date date = new Date();
        String slat = String.valueOf(date.getTime());
        //获取前端传递的密码---前端传递的密码需要经过RSA加密
        String password = req.getLoginPassword();
        //对密码进行解密
        Map<String, String> stringStringMap = RsaUtils.generateKey();
        String publicKey = stringStringMap.get("publicKeyStr");
        //原始密码
        String rawPassword = null;
        try {
            rawPassword = RsaUtils.decryptByPublicKey(password, publicKey);
        } catch (Exception e) {
            throw new ConditionException("密码解密失败");
        }

        //对密码进行MD5加密
        String md5Password = MD5Utils.MD5Lower(rawPassword, slat);
        //创建时间获取
        Timestamp timestamp = new Timestamp(System.currentTimeMillis());
        //开始存储用户的登录信息
        LoginInfo loginInfo = new LoginInfo();
        loginInfo.setLoginPhone(loginPhone);
        if (StringUtils.isNotBlank(req.getLoginEmail())) {
            loginInfo.setLoginEmail(req.getLoginEmail());
        }
        loginInfo.setLoginPassword(md5Password);
        loginInfo.setLoginSalt(slat);
        loginInfo.setEnableState(EnableStateEnums.START_USING.getCode());
        loginInfo.setDeleteState(DeleteStateEnums.UN_DELETED.getCode());
        loginInfo.setCreateTime(timestamp);
        loginInfo.setUpdateTime(timestamp);
        loginInfoDao.insert(loginInfo);
        //获取新添加的主键信息
        Long loginId = loginInfo.getLoginId();

        //添加用户信息
        UserInfo userInfo = new UserInfo();
        userInfo.setLoginId(loginId);
        userInfo.setUserNick(req.getUserNick());
        userInfo.setUserAvatar(req.getUserAvatar());
        userInfo.setUserSign(req.getUserSign());
        if (null == userInfo.getUserGender()) {
            //如果用户并未选择性别，默认用户性别未知
            userInfo.setUserGender(GenderEnums.GENDER_UNKONWN.getCode());
        } else {
            userInfo.setUserGender(req.getUserGender());
        }
        userInfo.setUserBirth(req.getUserBirth());
        userInfo.setEnableState(EnableStateEnums.START_USING.getCode());
        userInfo.setDeleteState(DeleteStateEnums.UN_DELETED.getCode());
        userInfo.setCreateTime(timestamp);
        userInfo.setUpdateTime(timestamp);
        userInfoDao.insert(userInfo);

        //为注册用户添加默认角色和默认权限
        userAuthService.insertUserDefaultRoleService(userInfo.getUserId());
    }

    @Override
    public String loginUserService(LoginInfo loginInfo) {
        //获取登录的手机号，并进行非空判断
        String loginPhone = loginInfo.getLoginPhone();
        if (StringUtils.isBlank(loginPhone)) {
            throw new ConditionException("手机号不能为空");
        }
        //根据手机号查询用户登录信息
        LoginInfo login = this.queryUserByPhoneService(loginPhone);
        if (null == login) {
            throw new ConditionException("当前用户不存在");
        }
        String password = loginInfo.getLoginPassword();
        //获取公钥，并对密码进行解密
        Map<String, String> stringStringMap = RsaUtils.generateKey();
        String publicKeyStr = stringStringMap.get("publicKeyStr");
        String rawPassword = null;
        try {
            rawPassword = RsaUtils.decryptByPublicKey(password, publicKeyStr);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        //获取盐值,通过盐值对密码加密，并与数据库记录密码进行比较
        String salt = login.getLoginSalt();
        String md5Password = MD5Utils.MD5Lower(rawPassword, salt);
        if (!md5Password.equals(login.getLoginPassword())) {
            throw new ConditionException("输入密码错误");
        }
        //根据用户的登录信息id查询用户id
        Long userId = userInfoDao.queryUserIdByLoginIdMapper(login.getLoginId());
        Map<String,Object> map = new HashMap<>();
        //存储的数据为用户的登录信息id
        map.put("loginId",login.getLoginId());
        map.put("userId",userId);
        String token = JwtUtil.generate(map);
        return token;
    }

    @Override
    public UserInfo getUserInfoService(Long currnetUserId) {
        //通过用户的登录id查询用户的信息
        UserInfo userInfo = userInfoDao.queryUserByLoginId(currnetUserId);
        return userInfo;
    }

    @Override
    public void updateUserInfoService(UserRequest request) {
        Timestamp timestamp = new Timestamp(System.currentTimeMillis());
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(request.getUserId());
        userInfo.setUserNick(request.getUserNick());
        userInfo.setUserAvatar(request.getUserAvatar());
        userInfo.setUserSign(request.getUserSign());
        userInfo.setUserGender(request.getUserGender());
        userInfo.setUserBirth(request.getUserBirth());
        userInfo.setUpdateTime(timestamp);

        //修改用户信息
        userInfoDao.update(userInfo);
    }

    /**
     * 根据用户id查询用户信息
     * @param userId
     * @return
     */
    @Override
    public UserInfo queryUserByIdService(Long userId) {
        return userInfoDao.queryById(userId);
    }

    @Override
    public List<UserInfo> getUserInfoByIdsService(List<Long> follwingIds) {
        return userInfoDao.queryUserInfoBatch(follwingIds);
    }

    @Override
    public List<UserInfo> getUserInfoByUserIdsService(List<Long> userIds) {
        return userInfoDao.queryUserInfoByUserIds(userIds);
    }

    @Override
    public PageResult<UserInfo> getUserInfoPageService(JSONObject params) {
        Integer number = params.getInteger("number");
        Integer size = params.getInteger("size");
        params.put("start",(number-1)*size);
        params.put("limit",size);
        Integer total = userInfoDao.queryPageCountUserInfo(params);
        List<UserInfo> userInfos = new ArrayList<>();
        if (total > 0) {
            userInfos = userInfoDao.queryUserInfoPageList(params);
            if (null == userInfos || userInfos.isEmpty()) {
                throw new ConditionException("并未查询到对应的用户信息");
            }
        }
        return new PageResult<>(total,userInfos);
    }

    @Override
    public Map<String, String> loginUserDtsService(LoginInfo loginInfo) {
        //获取登录的手机号，并进行非空判断
        String loginPhone = loginInfo.getLoginPhone();
        if (StringUtils.isBlank(loginPhone)) {
            throw new ConditionException("手机号不能为空");
        }
        //根据手机号查询用户登录信息
        LoginInfo login = this.queryUserByPhoneService(loginPhone);
        if (null == login) {
            throw new ConditionException("当前用户不存在");
        }
        String password = loginInfo.getLoginPassword();
        //获取公钥，并对密码进行解密
        Map<String, String> stringStringMap = RsaUtils.generateKey();
        String publicKeyStr = stringStringMap.get("publicKeyStr");
        String rawPassword = null;
        try {
            rawPassword = RsaUtils.decryptByPublicKey(password, publicKeyStr);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        //获取盐值,通过盐值对密码加密，并与数据库记录密码进行比较
        String salt = login.getLoginSalt();
        String md5Password = MD5Utils.MD5Lower(rawPassword, salt);
        if (!md5Password.equals(login.getLoginPassword())) {
            throw new ConditionException("输入密码错误");
        }
        //根据用户的登录信息id查询用户id
        Long userId = userInfoDao.queryUserIdByLoginIdMapper(login.getLoginId());

        Map<String,Object> map = new HashMap<>();
        //存储的数据为用户的登录信息id
        map.put("loginId",login.getLoginId());
        map.put("userId",userId);
        String accessToken = JwtUtil.generate(map);
        String refreshToken = JwtUtil.generateRefresh(map);

        //保存refreshToken到数据库中
        //删除数据库中的refreshToken
        Timestamp timestamp = new Timestamp(System.currentTimeMillis());
        RefreshTokenInfo refreshTokenInfo = new RefreshTokenInfo();
        refreshTokenInfo.setUserId(userId);
        refreshTokenInfo.setRefreshToken(refreshToken);
        refreshTokenInfo.setEnableState(0);
        refreshTokenInfo.setDeleteState(0);
        refreshTokenInfo.setCreateTime(timestamp);
        refreshTokenInfo.setUpdateTime(timestamp);
        refreshTokenInfoDao.deleteRefreshTokenDao(refreshToken,userId);
        refreshTokenInfoDao.insert(refreshTokenInfo);

        Map<String ,String> tokenMap = new HashMap<>();
        tokenMap.put("accessToken",accessToken);
        tokenMap.put("refreshToken",refreshToken);
        return tokenMap;
    }

    @Override
    public void logoutService(String refreshToken, Long userId) {
        refreshTokenInfoDao.deleteRefreshTokenDao(refreshToken,userId);
    }

    @Override
    public String refreshAccessToken(String refreshToken) {
        RefreshTokenInfo refreshTokenInfo = refreshTokenInfoDao.queryRefreshTokenDetail(refreshToken);

        String token = refreshTokenInfo.getRefreshToken();
        if (StringUtils.isBlank(token)) {
            throw new ConditionException("555","token过期");
        }
        Long userId = refreshTokenInfo.getUserId();
        return JwtUtil.generateUserId(userId);
    }

    //根据手机号查询相关用户信息
    public LoginInfo queryUserByPhoneService(String phone) {
        return loginInfoDao.queryUserByPhoneMapper(phone);
    }

    //根据登录信息id查询用户id
    public Long queryUserIdByLoginIdService(Long loginId) {
        return userInfoDao.queryUserIdByLoginIdMapper(loginId);
    }
}
